﻿/*******************************************************************************
 * AAEngine
 * Copyright (c) 2010 Mike Jarosch
 *
 * Original source PushButton Engine:
 * Copyright (C) 2009 PushButton Labs, LLC
 * For more information see http://www.pushbuttonengine.com
 *
 * This file is licensed under the terms of the MIT license, which is included
 * in the "MIT License.txt" file at the root directory of this SDK.
 ******************************************************************************/

using System;
using System.Collections.Generic;
using System.Xml.Linq;
using AAEngine.Engine.Core;

namespace AAEngine.Engine.Entities
{
    /// <summary>
    /// Game objects are referred to as entities. This interface defines the    
    /// behavior for an entity. A full featured implementation of this interface is    
    /// included, but is hidden so as to force using IEntity when storing references    
    /// to entities. To create a new entity, use New().
    /// </summary>
    /// <remarks>
    /// An entity by itself is a very light weight object. All it needs to store is    
    /// its name and a list of components. Custom functionality is added by creating    
    /// components and attaching them to entities.
    /// 
    /// 
    /// </remarks>
    public interface IEntity : IPropertyBag, IAAObject
    {
        /// <summary>
        /// When true, OnAdd/OnRemove callbacks are deferred. When set to false, any       
        /// pending callbacks are processed.
        /// </summary>
        bool Deferring { get; set; }

        /// <summary>
        /// Adds a component to the entity.
        /// </summary>
        /// <remarks>
        /// When a component is added, it will have its Register() method called       
        /// (or OnAdd if it is derived from EntityComponent). Also, Reset() will be       
        /// called on all components currently attached to the entity (or OnReset       
        /// if it is derived from EntityComponent).</
        /// </remarks>
        /// <param name="component">The component to add.</param>
        /// <param name="componentName">
        /// The name to set for the component. This is the value       
        /// to use in Find to get a reference to the component.       
        /// The name must be unique across all components on this entity.
        /// </param>
        /// <returns></returns>
        bool AddComponent(IEntityComponent component, string componentName);

        /// <summary>
        /// Removes a component from the entity.
        /// </summary>
        /// <remarks>
        /// When a component is removed, it will have its Unregister method called       
        /// (or OnRemove if it is derived from EntityComponent). Also, Reset will be       
        /// called on all components currently attached to the entity (or OnReset       
        /// if it is derived from EntityComponent).</
        /// </remarks>
        /// <param name="component">The component to remove.</param>
        void RemoveComponent(IEntityComponent component);

        /// <summary>
        /// Creates an XML description of this entity, including all currently attached
        /// components.
        /// </summary>
        /// <param name="xml">The xml object describing the entity. The parent tag should be
        /// included in this variable when the function is called, so only child tags
        /// need to be created.</param>
        void Serialize(XElement xml);

        /// <summary>
        /// Sets up this entity from an xml description.
        /// </summary>
        /// <param name="xml">The xml object describing the entity.</param>
        /// <param name="registerComponents">Set this to false to add components to the entity
        /// without registering them. This is used by the level manager to facilitate
        /// creating entities from templates.</param>
#if WINDOWS_PHONE || XBOX
        void Deserialize(XElement xml);
        void Deserialize(XElement xml, bool registerComponents);
#else
        void Deserialize(XElement xml, bool registerComponents = true);
#endif

        /// <summary>
        /// Gets a component of a specific type from this entity. If more than one
        /// component of a specific type exists, there is no guarantee which one
        /// will be returned. To retrieve all components of a specified type, use
        /// lookupComponentsByType.
        /// </summary>
        /// <param name="componentType">The type of the component to retrieve.</param>
        /// <returns>The component, or null if none of the specified type were found.</returns>
        IEntityComponent LookupComponentByType(Type componentType);

        /// <summary>
        /// Gets a list of all the components of a specific type that are on this
        /// entity.
        /// </summary>
        /// <param name="componentType">The type of the component to retrieve.</param>
        /// <returns>An IEnumerable containing all the components of the specified type on       
        /// this entity.</returns>
        IEnumerable<IEntityComponent> LookupComponentsByType(Type componentType);

        /// <summary>
        /// Gets a component that was registered with a specific name on this entity.
        /// </summary>
        /// <param name="componentName">The name of the component to retrieve. This corresponds
        /// to the second parameter passed to AddComponent.</param>
        /// <returns>The component with the specified name.</returns>
        IEntityComponent LookupComponentByName(string componentName);

        /// <summary>
        /// Gets a component of a specific type from this entity. If more than one 
        /// component of a specific type exists, there is no guarantee which one       
        /// will be returned. To retrieve all components of a specified type, use       
        /// FindComponents.
        /// </summary>
        /// <remarks>
        /// This check uses the is operator, so if you pass a parent type,       
        /// subclasses will be considered to match, as will things implementing       
        /// an interface you have passed.
        /// </remarks>
        /// <typeparam name="T">The type of the component to retrieve.</typeparam>
        /// <returns>The component, or null if one of the specified type was not found.</returns>
        //T FindComponent<T>() where T : IEntityComponent;

        /// <summary>
        /// Gets a component that was registered with a specific name on this entity.
        /// </summary>
        /// <remarks>
        /// This check uses the is operator, so if you pass a parent type,       
        /// subclasses will be considered to match, as will things implementing       
        /// an interface you have passed.
        /// </remarks>
        /// <typeparam name="T">The type of the component to return.</typeparam>
        /// <returns>The component, or null if one with the specific name was not found.</returns>
        //T FindComponent<T>(string name) where T : IEntityComponent;

        /// <summary>
        /// Gets a list of all the components of a specific type that are on this       
        /// entity.
        /// </summary>
        /// <remarks>
        /// This check uses the is operator, so if you pass a parent type,       
        /// subclasses will be considered to match, as will things implementing       
        /// an interface you have passed.
        /// </remarks>
        /// <typeparam name="T">The type of the component to retrieve.</typeparam>
        /// <returns>
        /// An IEnumerable containing all the components of the specified type on       
        /// this entity.
        /// </returns>
        //IEnumerable<T> FindComponents<T>() where T : IEntityComponent;

        /// <summary>
        /// Gets a component of a specific type from this entity. If more than one 
        /// component of a specific type exists, there is no guarantee which one       
        /// will be returned. To retrieve all components of a specified type, use       
        /// FindComponents.
        /// </summary>
        /// <param name="type">The type of the component to retrieve.</param>
        /// <returns>The component, or null if one with the specific name was not found.</returns>
        //IEntityComponent FindComponent(Type type);
    }
}
